/**
 * Alex Rodrigo de Oliveira - 06/30403
 * Rafaela Porto Osório - 06/94011
 */ 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <sys/msg.h>
#include "mqueue.h"
#include "debug.h"


/*
 * Funções auxiliares da main.
 */
static void get_args(int argc, char **argv, Job *job);
static void go_deamon(Job *job);
static void show_user(Job *job);


/*
 * Sub-funções auxiliares.
 */
static time_t get_time(char *delay);
static int get_repeats(char * n);
static void error();
static void check_digit(char *digit, int length);


/*
 * Main.
 */
int main(int argc, char **argv)
{
	Job job = { 0 };

	mqin = mqueue_obtain_in();
	mqout = mqueue_obtain_out();
	get_args(argc, argv, &job);
	go_deamon(&job);
	show_user(&job);
	return 0;
}


/*
 * Obtém argumentos passado como parâmetros pela linha de comando
 */
static void get_args(int argc, char **argv, Job *job)
{
	/* Valida quantidade de argumentos. */
	if (argc != 4) {
		error();
	}
	
	/* Valida os parâmetros e preenche os campo do job. */
	job->delay = get_time(argv[1]);
	strcpy(job->command, argv[2]);
	job->repeats = get_repeats(argv[3]);
}


/*
 * Envia mensagem ao deamon (executa_proc) avisando de um novo agendamento e
 * espera a resposta do sucesso com o id do processo, que é dado pelo deamon.
 */
static void go_deamon(Job *job)
{
	Msg msg = { 0 };

	/* Preenche os campos da mensagem. */
	msg.type = MSG_SUBMIT;
	msg.job = *job;

	/* Envia a mensagem ao deamon. */
	if (msgsnd(mqin, &msg, sizeof(Job), 0) < 0) {
        perror("Não foi possível enviar a mensagem para agendar o job");
        exit(1);
    }

	/* Recebe a mensagem de confirmação. */
	if (msgrcv(mqout, &msg, sizeof(Job), MSG_SUBMIT, 0) < 0) {
		perror("Não recebi confirmação de agendamento");
		exit(1);
	}
	job->id = msg.job.id;

	debug_print("Mensagem enviada. Delay = %d, Comando = %s, Repetições = %d\n",
			(int)job->delay, job->command, job->repeats);
	return;
}


/*
 * Confirma o agendamento de processo para ser executado e avisa ao usuário que
 * agendou do status do agendamento.
 */
static void show_user(Job *job)
{
	printf("O processo foi agendado para ser executado. Id do job = %d\n",
			job->id);
}


/*
 * Obtém o tempo já convertido. Recebe o delay fornecido pelo usuário e retorna
 * o tempo de alarme.
 */
static time_t get_time(char * delay)
{
	char hour[3] = { 0 }, min[3] = { 0 }, sec[3] = { 0 };
	time_t total_time;
		
	if (strlen(delay) != 8) {
		error();
	}

	strncpy(hour, &delay[0], 2);
	strncpy(min, &delay[3], 2);
	strncpy(sec, &delay[6], 2);

	check_digit(hour, strlen(hour));
	check_digit(min, strlen(min));
	check_digit(sec, strlen(sec));

	total_time = (atoi(sec) + atoi(min) * 60 + atoi(hour) * 3600);

	return total_time;
}


/*
 * Obtém os números de repetições. Checa validação do número informado.
 */ 
int get_repeats(char *n)
{
	check_digit(n, strlen(n));
	return atoi(n);
}


/*
 * Checa se o valor digitiado é somente dígito.
 * Recebe a string com o valor e o seu tamanho. Se o valor não for somente
 * dígito dá um erro.
 */ 
void check_digit(char *digit, int length)
{
	char aux[5] = { 0 };
	int control = -1, i = 0;

	strcpy(aux, digit);

	while (length > i) {
		control = isdigit(aux[i]);
		if (control == 0)
			error();
		i++;
	}
}


void error()
{
	puts("Você deve invocar o programa da seguinte forma:\n"
			"submete_proc hora:min:seg executável vezes");
	exit(1);
}
